﻿#region

using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using PTCN.CrossPlatform.BettingGame.CardGameFramework.Config;
using PTCN.CrossPlatform.BettingGame.DataAccess.Types;
using PTCN.CrossPlatform.BettingGame.Utilities;
using PTCN.CrossPlatform.BettingGame.Utilities.Message;
using PTCN.CrossPlatform.BettingGame.Bingo.Controllers;

#endregion

namespace PTCN.CrossPlatform.BettingGame.Bingo.Models
{
    public class SedieRoom : BettingGameSession
    {
        internal List<long> PlayersInGame { get; set; }
        internal double MoneyPercent { get; private set; }
        public List<int> History { get; private set; }
        public SedieGameLoop GameLoop { get; private set; }

        #region Bi Ngo property


        public DateTime DateTimeCreate { get; private set; }
        public DateTime DateTimeStart { get; private set; }
        public int Status { get; private set; }

        #endregion

        /// <summary>
        /// Nha cai
        /// </summary>
        public long Banker { get; internal set; }

        public SedieRoom(int minBet, byte moneyType, string password, byte rule)
            : base(GameIdTypes.XOC_DIA)
        {
            PlayersInGame = new List<long>(MaxPlayer);
            MinBet = minBet;
            MaxBet = 0;
            MoneyType = moneyType;
            MoneyPercent = GetMoneyPercent();

            if (!string.IsNullOrEmpty(password) && !string.IsNullOrWhiteSpace(password))
            {
                Password = password;
                IsPasswordProtected = true;
                IsPrivate = true;
            }
            else
            {
                IsPrivate = false;
            }
            History = new List<int>();
        }

        public void SetGameLoop(SedieGameLoop gameLoop)
        {
            GameLoop = gameLoop;
        }

        public override int GetClientTotalTime()
        {
            if (GameLoop == null) return 0;
            return ConfigTimeout.GetTimeout(GameLoop.Phrase) - ConfigTimeout.ClientDelay;
        }

        public override int GetClientElapsedTime()
        {
            return (GameLoop.Elapsed - ConfigTimeout.ClientDelay) >= 0
                ? (GameLoop.Elapsed - ConfigTimeout.ClientDelay)
                : 0;
        }

        protected override void PrepareDeactive()
        {
            GameLoop.StopTimer();
            SessionHandler.Instance.DeactiveSession(this);
        }

        public bool RemovePlayerWithReason(long accountId, string reason)
        {
            SediePlayer player = GetPlayer(accountId) as SediePlayer;
            if (player == null)
            {
                return false;
            }

            IReadOnlyList<string> connections = ConnectionHandler.Instance.GetConnections(accountId);
            foreach (var connectionId in connections)
            {
                ConnectionHandler.Instance.Clients.Group(SessionId.ToString()).playerLeave(accountId, reason);
                ConnectionHandler.Instance.Groups.Remove(connectionId, SessionId.ToString());
            }
            player.ClearData();
            RemovePlayer(accountId);
            return true;
        }

        public override List<long> RemovePlayerAfterEndGame()
        {
            try
            {
                long sessionid = SessionId;
                foreach (var key in Players.Keys)
                {
                    SediePlayer player = GetPlayer(key) as SediePlayer;
                    if (player == null) continue;
                    if (PlayerHandler.Instance.Contains(key))
                    {
                        //nguoi choi ko co ping len server
                        if (player.IdleTime() >= ConfigTimeout.MaxIdle)
                        {
                            RegisterLeaveGame(key);
                            player.ChangeConnectionStatus(ConnectionStatus.DISCONNECTED);
                            NLogManager.LogMessage(string.Format("Ping time out: {0} - AccountID: {1}", sessionid, key));
                        }
                        if (LeaveGameList.Contains(key) || player.ConnectionStatus == ConnectionStatus.DISCONNECTED)
                        {
                            player.ClearData();
                        }
                    }
                    else
                    {
                        RegisterLeaveGame(key);
                        player.ChangeConnectionStatus(ConnectionStatus.DISCONNECTED);
                        player.ClearData();
                    }
                }

                List<long> clone = new List<long>(LeaveGameList);
                List<long> outgame = base.RemovePlayerAfterEndGame();

                foreach (var accountid in outgame)
                {
                    IReadOnlyList<string> connections = ConnectionHandler.Instance.GetConnections(accountid);
                    foreach (var str in connections)
                    {
                        ConnectionHandler.Instance.Groups.Remove(str, SessionId.ToString());
                        if (clone.Contains(accountid))
                        {
                            ConnectionHandler.Instance.Clients.Client(str)
                                .playerLeave(accountid, CommonClientMessage.UserRegLeaveRoom);
                            ConnectionHandler.Instance.Clients.Group(SessionId.ToString())
                                .playerLeave(accountid, CommonClientMessage.OtherRegLeaveRoom);
                        }
                        else
                        {
                            ConnectionHandler.Instance.Clients.Client(str)
                                .playerLeave(accountid, CommonClientMessage.UserDisconnected);
                            ConnectionHandler.Instance.Clients.Group(SessionId.ToString())
                                .playerLeave(accountid, CommonClientMessage.OtherDisconnected);
                        }
                    }
                    NLogManager.LogMessage(string.Format("Quit room: {0} - AccountID: {1}", sessionid, accountid));
                }
                return outgame;
            }
            catch (Exception ex)
            {
                NLogManager.PublishException(ex);
            }
            return new List<long>();
        }

        /// <summary>
        /// Importance: Keep right order.
        /// </summary>
        public override void Dispose()
        {
            //Remove connections.
            foreach (var key in Players.Keys)
            {
                IReadOnlyList<string> connections = ConnectionHandler.Instance.GetConnections(key);
                foreach (var str in connections)
                {
                    ConnectionHandler.Instance.Clients.Client(str).playerLeave(key, "Hủy bàn chơi.");
                    ConnectionHandler.Instance.Groups.Remove(str, SessionId.ToString());
                }
            }

            //Clear cac collections.
            PlayersInGame.Clear();
            GameLoop.Dispose();
            GameLoop = null;
            base.Dispose();
        }

        public override void Refresh()
        {
            base.Refresh();
            PlayersInGame.Clear();
            GameLoop.Refresh();
        }

        public override void NotifyStartGame()
        {
            GameLoop.NotifyChangePhrase(SediePhrases.Waiting);
        }

        protected override void OwnerQuitAtStartGame(long oldOwner)
        {
            //throw new NotImplementedException();
        }

        protected override void WinnerQuitAtStartGame(long lastWinner)
        {
            //throw new NotImplementedException();
        }

        protected override void StopTimerIfNotEnough()
        {
            GameLoop.StopTimer();
        }

        public override bool EnableStartGame()
        {
            return IsEnough && !IsPlaying && !IsComfirming && Active;
        }

        public override JToken GetCurrentGameState()
        {
            throw new NotImplementedException();
        }

        public override bool CanBePlayer(AccountDb account)
        {
            if (account == null)
            {
                return false;
            }
            long amount = PenaltyMoney.GetPlayerReqMoney(MinBet);
            return account.IsEnoughMoney(amount, MoneyType);
        }

        public bool CanBeBanker(AccountDb account)
        {
            if (account == null)
            {
                return false;
            }
            long amount = PenaltyMoney.GetBankerReqMoney(MinBet, CountPlayers);
            return account.IsEnoughMoney(amount, MoneyType);
        }

        public override JToken CloneData(long accountId)
        {
            try
            {
                JToken obj = JToken.FromObject(this);
                foreach (JToken player in obj["Players"].Values())
                {
                    if (player == null)
                        continue;

                    long pAccountID = long.Parse(player["AccountID"].ToString());
                    if (pAccountID == accountId)
                        continue;

                    //mask username
                    if (player["Account"] == null) continue;
                    try
                    {
                        string username = player["Account"]["UserName"].ToString();
                        username = StringUtil.MaskUserName(username);
                        player["Account"]["UserName"].Replace(JToken.FromObject(username));
                    }
                    catch (Exception ex)
                    {
                        NLogManager.PublishException(ex);
                    }
                }
                return obj;
            }
            catch (Exception ex)
            {
                NLogManager.PublishException(ex);
            }
            return null;
        }
    }
}